﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Api;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Security;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Creates an order comment.
    /// </summary>
    public class CreateOrderComment : CreateComment<OrderCommentEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SALES");
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .IsVerified()
                    .Rule((ctx, uow) =>
                    {
                        var customer = ctx.Customer(uow);
                        if(customer == null || !customer.Flags.HasFlag(CustomerFlags.Active))
                            return false;
                        var order = uow.Execute(new GetOrder
                        {
                            EntityID = HolderID
                        }).Result;
                        if(order == null)
                            return false;
                        return order.Customer.Equals(customer);
                    });
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .IsVerified()
                    .Rule((ctx, uow) =>
                    {
                        var seller = ctx.Seller(uow);
                        if(seller == null || !seller.Flags.HasFlag(SellerFlags.Active))
                            return false;
                        var order = uow.Execute(new GetOrder
                        {
                            EntityID = HolderID
                        }).Result;
                        if(order == null)
                            return false;
                        return order.Seller.Equals(seller);
                    });
            }
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public OrderCommentFlags Flags
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether to suppress the notification(s).
        /// </summary>
        public bool SuppressNotification
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out OrderCommentEntity result)
        {
            base.Work(uow, out result);
            if(SuppressNotification) 
                return;
            var order = uow.Execute(new GetOrder
            {
                EntityID = result.HolderID
            }).Result;
            try
            {
                uow.Execute(new EnqueueOrderCommentNotification
                {
                    CommentID = result.EntityID,
                    RecipientID = order.Seller.Account.EntityID
                });
                if(Flags.HasFlag(OrderCommentFlags.Public))
                {
                    uow.Execute(new EnqueueOrderCommentNotification
                    {
                        CommentID = result.EntityID,
                        RecipientID = order.Customer.Account.EntityID
                    });
                }
            }
            catch(Exception ex)
            {
                uow.Execute(new CreateLogRecordFromException
                {
                    Ex = ex
                });
            }
        }

        protected override void Construct(IUnitOfWork uow, OrderCommentEntity entity)
        {
            base.Construct(uow, entity);

            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Updates an order comment.
    /// </summary>
    public class UpdateOrderComment : UpdateComment<OrderCommentEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SALES");
            }
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public OrderCommentFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Revise(IUnitOfWork uow, OrderCommentEntity entity)
        {
            base.Revise(uow, entity);

            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the order comment.
    /// </summary>
    public class DeleteOrderComment : DeleteComment<OrderCommentEntity>,
        ISecuredOperation, IApiOperation
    {
        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SALES");
            }
        }
    }

    /// <summary>
    /// Gets the order comment by identifier.
    /// </summary>
    public class GetOrderComment : GetComment<OrderCommentEntity>,
        IApiOperation
    {
    }

    #endregion

    #region __Search__

    /// <summary>
    /// Search over order comment collection.
    /// </summary>
    public class SearchOrderComments : SearchComments<OrderCommentEntity>,
        IApiOperation
    {
        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SearchOrderComments()
        {
            SortDir = SortDirection.Ascending;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the flag mask.
        /// </summary>
        public OrderCommentFlags FlagMask
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sort direction.
        /// </summary>
        public SortDirection SortDir
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<OrderCommentEntity> Build(IUnitOfWork uow, IQueryable<OrderCommentEntity> query)
        {
            query = base.Build(uow, query);
            query = query.FilterByFlags(x => (int)x.Flags, (int)FlagMask);
            query = query.OrderBy(x => x.CreatedOn, SortDir);
            return query;
        }

        #endregion
    }

    #endregion

    #region __Notification__

    /// <summary>
    /// Enqueues an order comment notification message.
    /// </summary>
    /// <remarks>
    /// Message template code: NORDCMNT
    /// Allowed tokens: [T:Recipient.EntityID], [T:Recipient.Guid], [T:Recipient.Email], [T:Recipient.Username],
    /// [T:OrderComment.Order.Customer.EntityID], [T:OrderComment.Order.Customer.Account.EntityID],
    /// [T:OrderComment.Order.Customer.Account.Email], [T:OrderComment.Order.Customer.Account.Username],
    /// [T:OrderComment.Order.Customer.Account.Guid], [T:OrderComment.Order.EntityID], [T:OrderComment.Order.Guid],
    /// [T:OrderComment.Order.Status], [T:OrderComment.Order.CreatedOn], [T:SellerComment.Account.EntityID],
    /// [T:SellerComment.Account.Username], [T:SellerComment.Account.Email], [T:SellerComment.Account.Guid],
    /// [T:OrderComment.CreatedOn], [T:OrderComment.Title], [T:OrderComment.Text]
    /// </remarks>
    public class EnqueueOrderCommentNotification : Operation<MessageEntity>
    {
        #region Properties

        /// <summary>
        /// Gets or sets the comment identifier.
        /// </summary>
        public int CommentID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the recipient account identifier.
        /// </summary>
        public int RecipientID
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out MessageEntity result)
        {
            var comment = uow.Execute(new GetOrderComment
            {
                ThrowsException = true,
                EntityID = CommentID
            }).Result;
            var recipient = uow.Execute(new GetAccount
            {
                ThrowsException = true,
                EntityID = RecipientID
            }).Result;
            var usrLocale = recipient.LocalizationProfile;
            int utcOffset = usrLocale.TimeZone.UtcOffset;
            string dtFmt = usrLocale.Country.DateTimeFormat;
            var order = uow.Execute(new GetOrder
            {
                EntityID = comment.HolderID
            }).Result;
            var customer = order.Customer;

            result = uow.Execute(new CreateTemplatedMessageByCode
            {
                TemplateCode = "NORDCMNT",
                LanguageID = usrLocale.Language.EntityID,
                Replacements = new Dictionary<String, String>
                {
                    {"Recipient.EntityID", recipient.EntityID.ToString()},
                    {"Recipient.Email", recipient.Email},
                    {"Recipient.Username", recipient.Username},
                    {"Recipient.Guid", recipient.Guid.ToString()},
                    {"OrderComment.Order.Customer.EntityID", customer.EntityID.ToString()},
                    {"OrderComment.Order.Customer.Account.EntityID", customer.Account.EntityID.ToString()},
                    {"OrderComment.Order.Customer.Account.Email", customer.Account.Email},
                    {"OrderComment.Order.Customer.Account.Username", customer.Account.Username},
                    {"OrderComment.Order.Customer.Account.Guid", customer.Account.Guid.ToString()},
                    {"OrderComment.Order.EntityID", order.EntityID.ToString()},
                    {"OrderComment.Order.Guid", order.Guid.ToString()},
                    {"OrderComment.Order.Status", FlagsHelper.G1_Flags(order.Flags).ToString()},
                    {"OrderComment.Order.CreatedOn", order.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt)},
                    {"OrderComment.CreatedOn", comment.CreatedOn.ToLocal(utcOffset).ToStringByFmt(dtFmt)},
                    {"OrderComment.Title", comment.Title},
                    {"OrderComment.Text", comment.Text}
                },
                To = recipient.Email,
                Flags = MessageFlags.Active
            }).Result;
        }

        #endregion
    }

    #endregion
}
